package com.magnificent.atlantis.server.database;

import com.magnificent.atlantis.common.entity.ServerMeeting;
import com.magnificent.atlantis.common.entity.ServerUser;
import com.magnificent.atlantis.common.entity.research.ServerUserInteraction;
import com.magnificent.commons.db.datasource.ObjectEntity;
import org.hibernate.Session;

import java.util.ArrayList;
import java.util.List;

/**
 * User: Babanin
 * Date: 04.04.2009
 * Time: 0:48:09
 */
public class AtlantisDataSource {
    private Session session;
    private static AtlantisDataSource instance;
    private List<DataSourceListener> listeners;

    private AtlantisDataSource() {
        HibernateUtil.getSessionFactory();
        listeners = new ArrayList<DataSourceListener>();
    }

    public void delete(ObjectEntity o) {
        session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        session.delete(o);

        session.getTransaction().commit();
        fireDataSourceChanged(o.getClass());
    }

    public void persist(ObjectEntity o) {
        session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        session.save(o);

        session.getTransaction().commit();
        fireDataSourceChanged(o.getClass());
    }

    public <T> List<T> getBeans(Class<T> clazz) {
        session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        //noinspection unchecked
        List<T> result = session.createQuery("from " + clazz.getName()).list();

        session.getTransaction().commit();
        return result;
    }

    public Session getSession() {
        session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        return session;
    }

    public void commit() {
        session.getTransaction().commit();
    }

    public boolean update(ObjectEntity objectEntity) {
        session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        session.merge(objectEntity);

        session.getTransaction().commit();

        fireDataSourceChanged(objectEntity.getClass());

        return true;
    }

    public void fireDataSourceChanged(Class clazz) {
        for (DataSourceListener listener : listeners) {
            listener.dataChanged(clazz);
        }
    }

    public void addDataSourceListener(DataSourceListener listener) {
        if (listener != null && !listeners.contains(listener)) {
            listeners.add(listener);
        } else {
            throw new IllegalStateException("dataSource listener");
        }
    }

    public void removeDataSourceListener(DataSourceListener listener) {
        if (listener != null && listeners.contains(listener)) {
            listeners.remove(listener);
        } else {
            throw new IllegalStateException("dataSource listener");
        }
    }

    public static AtlantisDataSource getInstance() {
        if (instance == null) {
            instance = new AtlantisDataSource();
        }

        return instance;
    }

    public void cleanAllByClass(Class clazz) {
        for (Object entity : getBeans(clazz)) {
            delete((ObjectEntity) entity);
        }
    }

    public void clean(Class clazz) {
        session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();

        session.createQuery("delete " + clazz.getName());

        session.getTransaction().commit();
    }


    public ServerMeeting getMeeting(int meetingId) {
        Session session = AtlantisDataSource.getInstance().getSession();
        return (ServerMeeting) session.createQuery("from ServerMeeting where id =" + meetingId).uniqueResult();
    }

    public List<ServerUserInteraction> getInteractions(ServerUser serverUserOne, ServerUser serverUserTwo) {
        Session session = getSession();

        List<ServerUserInteraction> result = new ArrayList<ServerUserInteraction>();
        result.addAll(
                session.createQuery(
                        "from ServerUserInteraction where " +
                                "(requestUserId = " + serverUserOne.getId() + " " +
                                    "and responseUserId = " + serverUserTwo.getId() + ") " +
                                "or (requestUserId = " + serverUserOne.getId() + " " +
                                    "and responseUserId = " + serverUserTwo.getId() + ")"
                ).list()
        );

        return result;
    }

    public List<ServerUser> getUsers() {
        return getBeans(ServerUser.class);
    }

}
